#!/usr/bin/python3
"""
Create NetworkManager configuration files.

This stages allows to create NetworkManager configuration files in the
location specified via `path` with the `settings` provided. Only a
subset of the all options are currently supported.

The stage will use `true` and `false` for boolean values and `,` as
list separator.

NetworkManger looks in the following locations for configuration files:
    - /etc/NetworkManager/NetworkManager.conf
    - /etc/NetworkManager/conf.d/name.conf
    - /usr/lib/NetworkManager/conf.d/name.conf,

 and also in the following locations that very likely should not be used:
    - /run/NetworkManager/conf.d/name.conf
    -/var/lib/NetworkManager/NetworkManager-intern.conf
"""

import configparser
import os
import sys

import osbuild.api


SCHEMA = r"""
"definitions": {
  "device-list": {
    "type": "array",
    "minItems": 1,
    "items": {
      "type": "string"
    }
  },
  "str-array": {
    "type": "array",
    "minItems": 1,
    "items": {
      "type": "string"
    }
  },
  "device": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "managed": {
        "type": "boolean"
      },
      "wifi.scan-rand-mac-address": {
        "type": "boolean"
      }
    }
  },
  "global-dns-domain": {
    "type": "object",
    "additionalProperties": false,
    "required": ["servers"],
    "properties": {
      "servers": {
        "type": "array",
        "minItems": 1,
        "items": {
          "type": "string"
        }
      }
    }
  }
},
"additionalProperties": false,
"required": ["path", "settings"],
"properties": {
  "path": {
    "type": "string"
  },
  "settings": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "main": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "no-auto-default": {
            "$ref": "#/definitions/device-list"
          },
          "plugins": {
            "$ref": "#/definitions/str-array"
          }
        }
      },
      "device": {
        "type": "array",
        "minItems": 1,
        "items": {
          "type": "object",
          "additionalProperties": false,
          "required": ["config"],
          "properties": {
            "name": {
              "type": "string"
            },
            "config": {
              "$ref": "#/definitions/device"
            }
          }
        }
      },
      "global-dns-domain": {
        "type": "array",
        "minItems": 1,
        "items": {
          "type": "object",
          "additionalProperties": false,
          "required": ["name", "config"],
          "properties": {
            "name": {
              "type": "string"
            },
            "config": {
              "$ref": "#/definitions/global-dns-domain"
            }
          }
        }
      },
      "keyfile": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "unmanaged-devices": {
            "$ref": "#/definitions/device-list"
          }
        }
      }
    }
  }
}
"""


def make_value(value):
    if isinstance(value, list):
        val = ",".join(value)
    elif isinstance(value, bool):
        val = "true" if value else "false"
    else:
        val = str(value)
    return val


def make_section(cfg, name, settings):
    if not cfg.has_section(name):
        cfg.add_section(name)

    for key, value in settings.items():
        val = make_value(value)
        cfg.set(name, key, val)


def make_named_section(cfg, name: str, section):

    config = section["config"]
    suffix = section.get("name")
    if suffix:
        name = f"{name}-{suffix}"

    make_section(cfg, name, config)


def main(tree, options):
    path = options["path"]
    settings = options["settings"]

    cfgfile = os.path.join(tree, path.lstrip("/"))

    cfgpath = os.path.dirname(cfgfile)
    os.makedirs(cfgpath, exist_ok=True)

    cfg = configparser.ConfigParser()
    cfg.optionxform = lambda o: o

    for name, items in settings.items():

        if isinstance(items, dict):
            make_section(cfg, name, items)
        elif isinstance(items, list):
            for item in items:
                make_named_section(cfg, name, item)
        else:
            raise ValueError(f"Invalid section type: {type(items)}")

    with open(cfgfile, "w") as f:
        os.fchmod(f.fileno(), 0o600)
        cfg.write(f, space_around_delimiters=False)

    return 0


if __name__ == '__main__':
    args = osbuild.api.arguments()
    r = main(args["tree"], args["options"])
    sys.exit(r)
